#pragma once
#include<string>
#include<unistd.h>
#include<vector>
#include<iostream>
#include<fstream>
#include"../source/Log2.hpp"
#include<unordered_map>
#include<sys/types.h>
#include<sys/stat.h>
#include<regex>
#include"../source/server.hpp"  //used Buffer

std::unordered_map<int, std::string> _statu_msg = {
    {100,  "Continue"},
    {101,  "Switching Protocol"},
    {102,  "Processing"},
    {103,  "Early Hints"},
    {200,  "OK"},
    {201,  "Created"},
    {202,  "Accepted"},
    {203,  "Non-Authoritative Information"},
    {204,  "No Content"},
    {205,  "Reset Content"},
    {206,  "Partial Content"},
    {207,  "Multi-Status"},
    {208,  "Already Reported"},
    {226,  "IM Used"},
    {300,  "Multiple Choice"},
    {301,  "Moved Permanently"},
    {302,  "Found"},
    {303,  "See Other"},
    {304,  "Not Modified"},
    {305,  "Use Proxy"},
    {306,  "unused"},
    {307,  "Temporary Redirect"},
    {308,  "Permanent Redirect"},
    {400,  "Bad Request"},
    {401,  "Unauthorized"},
    {402,  "Payment Required"},
    {403,  "Forbidden"},
    {404,  "Not Found"},
    {405,  "Method Not Allowed"},
    {406,  "Not Acceptable"},
    {407,  "Proxy Authentication Required"},
    {408,  "Request Timeout"},
    {409,  "Conflict"},
    {410,  "Gone"},
    {411,  "Length Required"},
    {412,  "Precondition Failed"},
    {413,  "Payload Too Large"},
    {414,  "URI Too Long"},
    {415,  "Unsupported Media Type"},
    {416,  "Range Not Satisfiable"},
    {417,  "Expectation Failed"},
    {418,  "I'm a teapot"},
    {421,  "Misdirected Request"},
    {422,  "Unprocessable Entity"},
    {423,  "Locked"},
    {424,  "Failed Dependency"},
    {425,  "Too Early"},
    {426,  "Upgrade Required"},
    {428,  "Precondition Required"},
    {429,  "Too Many Requests"},
    {431,  "Request Header Fields Too Large"},
    {451,  "Unavailable For Legal Reasons"},
    {501,  "Not Implemented"},
    {502,  "Bad Gateway"},
    {503,  "Service Unavailable"},
    {504,  "Gateway Timeout"},
    {505,  "HTTP Version Not Supported"},
    {506,  "Variant Also Negotiates"},
    {507,  "Insufficient Storage"},
    {508,  "Loop Detected"},
    {510,  "Not Extended"},
    {511,  "Network Authentication Required"}
 };

 std::unordered_map<std::string, std::string> _mime_msg = {
    {".aac",        "audio/aac"},
    {".abw",        "application/x-abiword"},
    {".arc",        "application/x-freearc"},
    {".avi",        "video/x-msvideo"},
    {".azw",        "application/vnd.amazon.ebook"},
    {".bin",        "application/octet-stream"},
    {".bmp",        "image/bmp"},
    {".bz",         "application/x-bzip"},
    {".bz2",        "application/x-bzip2"},
    {".csh",        "application/x-csh"},
    {".css",        "text/css"},
    {".csv",        "text/csv"},
    {".doc",        "application/msword"},
    {".docx",       "application/vnd.openxmlformats\
        officedocument.wordprocessingml.document"},
    {".eot",        "application/vnd.ms-fontobject"},
    {".epub",       "application/epub+zip"},
    {".gif",        "image/gif"},
    {".htm",        "text/html"},
    {".html",       "text/html"},
    {".ico",        "image/vnd.microsoft.icon"},
    {".ics",        "text/calendar"},
    {".jar",        "application/java-archive"},
    {".jpeg",       "image/jpeg"},
    {".jpg",        "image/jpeg"},
    {".js",         "text/javascript"},
    {".json",       "application/json"},
    {".jsonld",     "application/ld+json"},
    {".mid",        "audio/midi"},
    {".midi",       "audio/x-midi"},
    {".mjs",        "text/javascript"},
    {".mp3",        "audio/mpeg"},
    {".mpeg",       "video/mpeg"},
    {".mpkg",       "application/vnd.apple.installer+xml"},
    {".odp",        "application/vnd.oasis.opendocument.presentation"},
    {".ods",        "application/vnd.oasis.opendocument.spreadsheet"},  
    {".odt",       "application/vnd.oasis.opendocument.text"},  
    {".oga",     "audio/ogg"},    
    {".ogv",    "video/ogg"},     
    {".ogx",  "application/ogg"},      
    {".otf",    "font/otf"},     
    {".png",    "image/png"},     
    {".pdf",    "application/pdf"},     
    {".ppt",     "application/vnd.ms-powerpoint"},    
    {".pptx",       "application/vnd.openxml-ormatsofficedocument.presentationml.presentation"},  
    {".rar",   "application/x-rar-compressed"},     
    {".rtf",   "application/rtf"},     
    {".sh",     "application/x-sh"},    
    {".svg",      "image/svg+xml"},   
    {".swf",     "application/x-shockwave-flash"},    
    {".tar",     "application/x-tar"},   
    {".tif",      "image/tiff"},   
    {".tiff",     "image/tiff"},   
    {".ttf",     "font/ttf"},   
    {".txt",      "text/plain"},   
    {".vsd",      "application/vnd.visio"},   
    {".wav",     "audio/wav"},    
    {".weba",    "audio/webm"},   
    {".webm",    "video/webm"},   
    {".webp",    "image/webp"},    
    {".woff",      "font/woff"},  
    {".woff2",    "font/woff2"},   
    {".xhtml",    "application/xhtml+xml"},  
    {".xls",     "application/vnd.ms-excel"},   
    {".xlsx",     "application/vnd.openxmlformatsofficedocument.spreadsheetml.sheet"},   
    {".xml",  "application/xml"},      
    {".xul", "application/vnd.mozilla.xul+xml"},       
    {".zip",  "application/zip"},       
    {".3gp",  "video/3gpp"},       
    {".3g2",  "video/3gpp2"},       
    {".7z",  "application/x-7z-compressed"}  
};
         
class Util
{
public:
    static size_t Split(const std::string &src, const std::string &sep, std::vector<std::string> *arry){
        size_t offset = 0;
        while (offset < src.size())
        {
            size_t pos = src.find(sep, offset);//分割符位置
            std::cout<<pos<<std::endl;
            std::cout<<"std::string::npos:"<<std::string::npos<<std::endl;
            if (pos == std::string::npos)  
            {
                if (pos == src.size()) //多余
                    break;
                arry->push_back(src.substr(offset));
                return arry->size();
            }
            if (pos == offset)// offset处找到
            { 
                offset = pos + sep.size();
                continue; // 当前字串是一个空的,没有内容
            }
            arry->push_back(src.substr(offset, pos - offset));
            offset = pos + sep.size();
        }
        return arry->size();
    }
    //读取文件的所有内容,将读取的内容放到一个Buffer中
    static bool ReadFile(const std::string &filename, std::string *buf){
        std::ifstream ifs(filename, std::ios::binary);//input站在进程（计算机内存）的角度
        if(ifs.is_open() == false){
            printf("OPEN %s FILE FAILED!!!", filename.c_str());
            return false;
        }
        size_t fsize = 0;
        ifs.seekg(0,ifs.end);//跳转读写位置到末尾
        fsize = ifs.tellg(); //获取当前位置相对于起始位置的偏移量,\
        从末尾偏移刚好就是文件大小
        ifs.seekg(0,ifs.beg);
        buf->resize(fsize);
        ifs.read(&((*buf)[0]),fsize); //转为char*类型
        if(ifs.good() == false){
            printf("READ %s FILE FAILED!!",filename.c_str());
            ifs.close();
            return false;
        }
        ifs.close();
        return true;
    }
    //向文件写入数据
    static bool WriteFile(const std::string &filename, const std::string &buf){//输入
        std::ofstream ofs(filename, std::ios::binary | std::ios::trunc);
        if(ofs.is_open() == false){
            printf("OPEN %s FILE FAILED!!",filename.c_str());
            return false;
        }
        ofs.write(buf.c_str(),buf.size());
        if(ofs.good() == false){
            ERR_LOG("WRITR %s FILE FAILED!", filename.c_str());
            ofs.close();
            return false;
        }
        ofs.close();
        return true;
    }

    //URL编码，避免URL中资源路径与查询字符串中的特殊字符与http请求中特殊字符产生歧义
    //编码格式：将特殊字符的ascii值，转换为两个16进制（0~F）字符,前缀%，C++ -> C%2B%2B,\
    2B一共8位ascii, RFC3986文档规定，编码格式 %HH,
    //W3C标准规定,查询字符串中的空格,需要编码为+,解码则是 + 转空格
    //大多数编程语言（如 C++、Python 等）在处理注释时会忽略续行符 \,
    //因为它被视为注释的一部分，而不是代码的一部分。因此，在注释中使用续行符不会起到“换行”的作用。
    static std::string UrlEncode(const std::string url,bool convert_space_to_plus){
        std::string res;
        for(auto &c:url){
            if(c == '.'|| c == '-' || c == '_' || c=='~' || isalnum(c)){
                res += c;
                continue;
            }
            if(c == ' '&&convert_space_to_plus == true){
                res += '+';
                continue;
            }
            char tmp[4] = {0};
            snprintf(tmp, 4, "%%%02X",c);
            res += tmp;
        }
        return res;
    }
    static char HEXTOI(char c){
        if(c >= '0' && c<='9'){
            return c-'0';
        }else if(c >= 'a' && c <= 'z'){
            return c-'a' + 10;
        }else if(c >= 'A' && c <= 'Z'){
            return c-'A'+10;
        }
        return -1;
    }
    static std::string UrlDecode(const std::string url, bool convert_plus_to_space){
        std::string res;
        for(int i=0;i<url.size();i++){
            if(url[i]== '+'&&convert_plus_to_space == true){
                res += ' ';
                continue;
            }
            if(url[i] == '%' && (i + 2) < url.size()){
                char v1 = HEXTOI(url[i+1]);
                char v2 = HEXTOI(url[i+2]);
                char v = v1 *16 + v2;
                res += v;
                i += 2; //逃过后两字节
                continue;
            }
            res += url[i];
        }
        return res;
    }
    //响应状态码的描述信息获取
    static std::string StatuDesc(int statu){
        auto it = _statu_msg.find(statu);
        if(it != _statu_msg.end()){
            return it->second;
        }
        return "UnKnow";
    }


    //根据文件后缀名获取文件mime
    static std::string ExtMime(const std::string &filename){
        size_t pos = filename.find_last_of('.');//从后面找不是
        if(pos == std::string::npos){
            return "application/octet-stream";
        }
        //根据扩展名,获取mime
        std::string ext = filename.substr(pos);
        auto it = _mime_msg.find(ext);
        if(it == _mime_msg.end()){
            return "application/octet-stream";
        }
        return it->second;
    }
    //判断一个文件是否是一个目录
    static bool IsDirectory(const std::string &filename){
        struct stat st;
        int ret = stat(filename.c_str(),&st);
        if(ret < 0){ //
            return false;
        }
        return S_ISDIR(st.st_mode);
    }
    //判断一个文件是否是一个普通文件
    static bool IsRegular(const std::string &filename){
        struct stat st;
        int ret = stat(filename.c_str(),&st);
        if(ret < 0){
            return false;
        }
        return S_ISREG(st.st_mode);
    }
    //http请求的资源路径是否有效
    static bool ValidPath(const std::string &path){
        std::vector<std::string> subdir;
        Split(path,"/", &subdir);
        int level = 0;
        for(auto &dir : subdir){
            if(dir == ".."){ 
                level--;
                if(level < 0) return false;//访问外层取消
                continue;
            }
            level++;
        }
        return true;
    }
};

class HttpRequest{
public:
    std::string _method;//请求方法
    std::string _path;  //资源路径
    std::string _version;   //协议版本
    std::string _body;      //请求正文
    std::smatch _matches;   //资源路径的正则提取数据
    std::unordered_map<std::string, std::string> _headers; //头部字段
    std::unordered_map<std::string, std::string> _params;   //查询字符串
public:
    HttpRequest():_version("HTTP/1.1"){}
    void ReSet(){
        _method.clear();
        _path.clear();
        _version = "HTTP/1.1";
        _body.clear();
        std::smatch match;
        _matches.swap(match);
        _headers.clear();
        _params.clear();
    }
    // 插入头部字段
    void SetHeader(const std::string &key, const std::string &val){
        _headers.insert(std::make_pair(key, val));
    }
    //判断是否存在指定头部字段
    bool HasHeader(const std::string &key) const {
        auto it = _headers.find(key);
        if(it == _headers.end()){
            return false;
        }
        return true;
    }
    //获取指定头部字段的值
    std::string GetHeader(const std::string &key) const {
        auto it = _headers.find(key);
        if(it == _headers.end()){
            return "";
        }
        return it->second;
    }
    // 插入查询字符串
    void SetParam(const std::string &key, const std::string &val){
        _params.insert(std::make_pair(key,val));
    }
    //判断是否有某个指定的查询字符串
    bool HasParam(const std::string &key){
        auto it = _params.find(key);
        if(it == _params.end()){
            return false;
        }
        return true;
    }
    //获取指定的查询字符串
    std::string GetParam(const std::string &Key) const{
        auto it = _params.find(Key);
        if(it == _params.end()){
            return "";
        }
        return it->second;
    }
    //获取正文长度
    size_t ContentLength() const{
        bool ret = HasHeader("Content-Length");
        if(ret == false){
            return 0;
        }
        std::string clen = GetHeader("Content-Length");
        return std::stol(clen);
    }
    //判断是否是短连接
    bool Close() const {
        if(HasHeader("Connection") == true && GetHeader("Connection") == "keep-alive"){
            return false;
        }
        return true;
    }
};

class HttpResponse{
public:
    int _statu;
    bool _redirect_flag;
    std::string _body;
    std::string _redirect_url;
    std::unordered_map<std::string, std::string> _headers;
public:
    HttpResponse():_redirect_flag(false), _statu(200) {}
    HttpResponse(int statu):_redirect_flag(false), _statu(statu) {}
    void ReSet(){
        _statu = 200;
        _redirect_flag = false;
        _body.clear();
        _redirect_url.clear();
        _headers.clear();
    }
     // 插入头部字段
     void SetHeader(const std::string &key, const std::string &val){
        _headers.insert(std::make_pair(key, val));
    }
    //判断是否存在指定头部字段
    bool HasHeader(const std::string &key) const {
        auto it = _headers.find(key);
        if(it == _headers.end()){
            return false;
        }
        return true;
    }
    //获取指定头部字段的值
    std::string GetHeader(const std::string &key) const {
        auto it = _headers.find(key);
        if(it == _headers.end()){
            return "";
        }
        return it->second;
    }
    void SetContent(const std::string &body, const std::string &type = "text/html"){
        _body = body;
        SetHeader("Content-Type",type); 
    }
    void SetRedirect(const std::string &url, int statu = 302){
        _statu = statu;
        _redirect_flag = true;
        _redirect_url = url;
    }
    bool close(){
        if(HasHeader("Connection") == true && GetHeader("Connection")=="keep-alive"){
            return false;
        }
        return true;
    }
};

typedef enum{
    RECV_HTTP_ERROR,
    RECV_HTTP_LINE,
    RECV_HTTP_HEAD,
    RECV_HTTP_BODY,
    RECV_HTTP_OVER
}HttpRecvStatu; //获取上下文的状态

#define MAX_LINE 8192
class HttpContext{
private:
    int _resp_statu;//相应状态码
    HttpRecvStatu _recv_statu; //当前接受及解析的阶段状态
    HttpRequest _request;       //已经解析得到的请求信息
private:
    bool ParseHttpLine(const std::string &line){
        std::smatch matches;    
        // (GET|HEAD|POST|PUT|DELETE) ([^?]*)(?:\\?(.*))? (HTTP/1\\.[01])(?:\n|\r\n)?
        std::regex e("(GET|HEAD|POST|PUT|DELETE) ([^?]*)(?:\\?(.*))? (HTTP/1\\.[01])(?:\n|\r\n)?"\
            , std::regex::icase);   //正则表达式,字符串间不能用\连接符,会被当成字符
        bool ret = std::regex_match(line,matches,e);    //
        if(ret == false){
            _recv_statu = RECV_HTTP_ERROR;
            _resp_statu = 400;
            return false;
        }
        //0 : GET /bitejiuyeke/login?user=xiaoming&pass=123123 HTTP/1.1
        //1 : GET
        //2 : /bitejiuyeke/login
        //3 : user=xiaoming&pass=123123
        //4 : HTTP/1.1
        //请求⽅法的获取
        std::cout<<"matches[0]:"<<matches[0]<<std::endl;
        std::cout<<"matches[1]:"<<matches[1]<<std::endl;
        std::cout<<"matches[2]:"<<matches[2]<<std::endl;
        std::cout<<"matches[3]:"<<matches[3]<<std::endl;
        std::cout<<"matches[4]:"<<matches[4]<<std::endl;
        sleep(5);

        _request._method = matches[1];
        //?, 
        //:: 全局域
        std::transform(_request._method.begin(), _request._method.end(),_request._method.begin(),::toupper); //对对象中的每个元素进行处理复到另一个对象中？
        
        // if(matches[2]=="/favicon.ico"){ //调试可删
        //     std::cout<<"false"<<std::endl;
        //     return false;
        // }else{
        //     std::cout<<"matches[2]:"<<matches[2]<<std::endl;
        //     std::string str("/favicon.ico");
        //     std::cout<<"str:"<<str<<"str.size():"<<str.size()<<std::endl;
        // }
        _request._path = Util::UrlDecode(matches[2],false); //没有W3C编码规则
        // std::cout<<"_request._path:"<<_request._path<<"_request._path.size():"<<_request._path.size()<<std::endl;
        if(_request._path=="/favicon.ico"){
            return false;
        }
        _request._version = matches[4];
        //查询字符串的获取
        std::vector<std::string> query_string_arry;
        // 账号密码
        std::string query_string = matches[3];
        // std::cout<<"query_string:"<<query_string<<std::endl;
        Util::Split(query_string,"&",&query_string_arry);
        
        for(auto &str : query_string_arry){
            size_t pos = str.find("="); 
            if(pos == std::string::npos){
                _recv_statu = RECV_HTTP_ERROR;
                _resp_statu = 400;
                return false;
            }
            std::string key = Util::UrlDecode(str.substr(0,pos),true);//W3C
            std::string val = Util::UrlDecode(str.substr(pos+1),true);
            _request.SetParam(key,val);
        }
        return true;
    }

    bool RecvHttpLine(Buffer *buf){
        if(_recv_statu != RECV_HTTP_LINE) return false;
        //1、获取一行数据, 带有末尾的换行
        std::string line = buf->GetLineAndPop();
        // std::cout<<"line:"<<line<<std::endl;
        //
        if(line.size() == 0){
             //缓冲区中的数据不⾜⼀⾏，则需要判断缓冲区的可读数据⻓度，如果很⻓了都不
            //⾜⼀⾏，这是有问题的
            if(buf->ReadAbleSize() > MAX_LINE){
                _recv_statu = RECV_HTTP_ERROR;
                _resp_statu = 414;
                return false;
            }
            return true;
        }
        if(line.size() > MAX_LINE){
            _recv_statu = RECV_HTTP_ERROR;
            _resp_statu = 414;
            return false;
        }
        bool ret = ParseHttpLine(line);
        if(ret == false){
            return false;
        }
        //首行处理完毕，进入头部获取阶段
        _recv_statu = RECV_HTTP_HEAD;
        return true;
    }

    bool RecvHttpHead(Buffer *buf){
        if(_recv_statu != RECV_HTTP_HEAD) return false;
        //2. 需要考虑的一些要素
        while(1){
            std::string line = buf->GetLineAndPop();
            if(line.size() == 0){
                if(buf->ReadAbleSize() > MAX_LINE){
                    _recv_statu = RECV_HTTP_ERROR;
                    _resp_statu = 414;
                    return false;
                }
                return true;
            }
            if(line.size() > MAX_LINE){
                _recv_statu = RECV_HTTP_ERROR;
                _resp_statu = 414;
                return false;
            }
            if(line == "\n" || line =="\r\n"){
                break;
            }
            bool ret = ParseHttpHead(line);
            if(ret == false){
                _recv_statu = RECV_HTTP_ERROR;
                return false;
            }
        }
        _recv_statu = RECV_HTTP_BODY;
        return true;
    }

    bool ParseHttpHead(std::string &line){
        if(line.back() == '\n') line.pop_back();
        if(line.back() == '\r') line.pop_back();
        size_t pos = line.find(": ");
        if(pos == std::string::npos){
            _recv_statu = RECV_HTTP_ERROR;
            _resp_statu = 400;
            return false;
        }
        std::string key = line.substr(0,pos);
        std::string val = line.substr(pos + 2);
        //查看报文头部head
        _request.SetHeader(key,val);
        return true;
    }

    bool RecvHttpBody(Buffer *buf){
        if(_recv_statu != RECV_HTTP_BODY) return false;
        //1.获取正文长度
        size_t content_length = _request.ContentLength();
        if(content_length == 0){
            _recv_statu = RECV_HTTP_OVER;
            return true;
        }
        size_t real_len = content_length - _request._body.size();//实际正文长度
        // 3. 接受正文放到body中，
        if(buf->ReadAbleSize() >= real_len){
            _request._body.append(buf->ReadPosition(),real_len);
            buf->MoveReadOffset(real_len);// 
            _recv_statu = RECV_HTTP_OVER;
            return true;
        }
        //缓冲区数据,无法满足当前正文的要求
        _request._body.append(buf->ReadPosition(),buf->ReadAbleSize());
        buf->MoveReadOffset(buf->ReadAbleSize());
        return true;
    }
    
public:
    HttpContext():_resp_statu(200), _recv_statu(RECV_HTTP_LINE){}
    void Reset(){
        _resp_statu = 200;
        _recv_statu = RECV_HTTP_LINE;
        _request.ReSet();
    }
    int RespStatu() { return _resp_statu; }
    HttpRecvStatu RecvStatu() { return _recv_statu; }
    HttpRequest &Request() { return _request; } 
    void RecvHttpRequest(Buffer *buf){
        switch(_recv_statu){
            case RECV_HTTP_LINE: RecvHttpLine(buf);
            case RECV_HTTP_HEAD: RecvHttpHead(buf);
            case RECV_HTTP_BODY: RecvHttpBody(buf);
        }
        return ;
    }
};

#define DEFALT_TIMEOUT 10

class HttpServer{
private:
    using Handler = std::function<void(const HttpRequest &, HttpResponse *)>;
    using Handlers = std::vector<std::pair<std::regex, Handler>>;
    Handlers _get_route;
    Handlers _post_route;
    Handlers _put_route;
    Handlers _delete_route;
    std::string _basedir;
    TcpServer _server;
private:
    void ErrorHandler(const HttpRequest &req, HttpResponse *rsp){
        std::string body;
        body += "<html>";
        body += "<head>";
        body += "<meta http-equiv='Context-Type' content='text/html;charset=utf-8'>";
        body += "</head>";
        body += "<body>";
        body += "<h1>";
        body += std::to_string(rsp->_statu);
        body += " ";
        body += Util::StatuDesc(rsp->_statu);
        body += "</h1>";
        body += "</body>";
        body += "</html>";
        //2、将页面数据，当作响应正文，放入rsp中
        rsp->SetContent(body,"text/html");
    }

    void WriteResponse(const PtrConnection &conn, const HttpRequest &req, HttpResponse &rsp){
        if(req.Close() == true){
            rsp.SetHeader("Connection","close");
        }else{
            rsp.SetHeader("Connection","keep-alive");
        }        
        if(rsp._body.empty() == false && rsp.HasHeader("Content-Length") == false){
            rsp.SetHeader("Content-Length", std::to_string(rsp._body.size()));
        }
        if(rsp._body.empty() == false && rsp.HasHeader("Content-Type") == false){
            rsp.SetHeader("Content-Length", "application/octet-stream");
        }
        if(rsp._redirect_flag == true){
            rsp.SetHeader("Location",rsp._redirect_url);
        }
        //2、将rsp的要素，按照http协议格式发送
        std::stringstream rsp_str;
        rsp_str<< req._version<<" "<<std::to_string(rsp._statu)<<" "<<Util::StatuDesc(rsp._statu)<<"\r\n";
        for(auto &head : rsp._headers){
            rsp_str<< head.first<<": "<< head.second<<"\r\n";//:后加空格
        }
        rsp_str<<"\r\n";
        rsp_str<<rsp._body;
        //3.发送数据.使用conn
        // std::cout<<"发送的数据为: "<<rsp_str.str()<<std::endl;
        conn->Send(rsp_str.str().c_str(), rsp_str.str().size());
    }
    // 判断是否是资源请求
    bool IsFileHandler(const HttpRequest &req) const {
        //1.必须设置了静态资源根目录
        if(_basedir.empty()){
            return false;
        }
        //2.请求方法，必须是GET /HEAD 请求方法
        if(req._method != "GET" && req._method != "HEAD"){
            return false;
        }
        //3.请求的资源路径必须是合法
        if(Util::ValidPath(req._path) == false){
            return false;
        }
        //4、请求的资源必须存在，且是普通文件   
        std::string req_path = _basedir + req._path;
        // std::cout<<"req_path:"<<req_path<<std::endl;
        if(req._path.back() == '/'){ 
            req_path += "index.html";
        }
        //5、是否是普通文件
        if(Util::IsRegular(req_path) == false){
            return false;
        }
        return true;
    }
    //静态资源的请求处理 -- 将静态资源文件的数据读取出来，放到rsp的_body中.并设置mime
    void FileHandler(const HttpRequest &req, HttpResponse *rsp){
        std::string req_path = _basedir + req._path;//
        if(req._path.back()=='/'){
            req_path += "index.html";
        }
        bool ret = Util::ReadFile(req_path, &rsp->_body);
        if(ret == false){
            return ;
        }
        std::string mime = Util::ExtMime(req_path);//获取mime
        rsp->SetHeader("Context-Type",mime);
        return ;
    }
    //功能性请求的分类处理,
    void Dispatcher(HttpRequest &req, HttpResponse *rsp, Handlers &handlers){
        for(auto &handler : handlers){
            const std::regex &re = handler.first;//使用正则表达式，对请求的资源路径进行正则匹配,匹配成功\
            就使用对应函数进行处理
           
            // std::string req_path = "/1234.txt";
            // if(req_path != req._path){
            //     std::cout<<"路径不正确"<<std::endl;
            // }
            const Handler &functor = handler.second;
            bool ret = std::regex_match(req._path, req._matches,re); 
            if(ret == false){
                std::cout<<"匹配错误?re:"<<req._path<<std::endl;
                continue;
            }
            return functor(req,rsp); //传入请求信息和空的rsp
        }
        rsp -> _statu = 404;
    }

    void Route(HttpRequest &req, HttpResponse *rsp){
        //1. 对请求进行分辨
        if(IsFileHandler(req) == true){
            return FileHandler(req,rsp);
        }
        if(req._method == "GET" || req._method == "HEAD"){
            return Dispatcher(req, rsp, _get_route); //_get_route对应的处理函数表
        }else if(req._method == "POST"){
            return Dispatcher(req,rsp,_post_route);
        }else if(req._method == "PUT"){
            std::cout<<"put"<<std::endl;
            return Dispatcher(req,rsp,_put_route);
        }else if(req._method == "DELETE"){
            return Dispatcher(req,rsp,_delete_route);
        }
        rsp -> _statu = 405;    //Method Not Al
        return ;
    }

    void OnConnected(const PtrConnection &conn){
        conn->SetContext(HttpContext());
        DBG_LOG("NEW CONNECTION %p",conn.get());
    }

    //缓冲区数据解析+处理
    void OnMessage(const PtrConnection &conn, Buffer *buffer){
        while(buffer->ReadAbleSize() > 0){
            //1. 获取上下文 //接口暂时没写
            HttpContext *context = conn->GetContext()->get<HttpContext>();
            //2. 同个上下文对缓冲区数据进行解析，得到HttpRequset对象
            context->RecvHttpRequest(buffer);
            HttpRequest &req = context->Request();
            HttpResponse rsp(context->RespStatu());//
            if(context -> RespStatu() >= 400){    //解析请求出错
                //进行错误响应，关闭连接
                ErrorHandler(req, &rsp);    //填充一个错误显示页面
                WriteResponse(conn, req, rsp);//组织相应发送给客户端
                context->Reset();
                buffer->MoveReadOffset(buffer->ReadAbleSize());//出错了就把缓冲区数据清空
                conn->Shutdown();
                return;
            }
            if(context->RecvStatu() != RECV_HTTP_OVER){
                return;
            }
            //3、请求路由 + 业务处理
            Route(req,&rsp);
            //4、对HttpResponse进行组织发送
            // std::cout<<"对HttpResponse进行组织发送前的rsp->_statu: "<<rsp._statu<<std::endl;
            WriteResponse(conn,req,rsp);
            //5、重置上下文
            context->Reset();
            //6、根据长短连接判断是否关闭连接或者继续处理
            std::cout<<"rsp.close():"<<rsp.close()<<std::endl;
            if(rsp.close() == true) conn->Shutdown();
        }
        return ;
    }
    
public:
    HttpServer(int port, int timeout = DEFALT_TIMEOUT):_server(port){
        _server.EnableInactiveRelease(timeout);
        _server.SetCounnectedCallback(std::bind(&HttpServer::OnConnected,this,std::placeholders::_1));
        _server.SetMessageCallback(std::bind(&HttpServer::OnMessage,this,std::placeholders::_1\
            ,std::placeholders::_2));
    }
    void SetBaseDir(const std::string &path){
        assert(Util::IsDirectory(path) == true);
        _basedir = path;
    }
    void Get(const std::string &pattern, const Handler &handler){
        // std::cout<<"设置_get_route表的正则,pattern: "<<pattern<<std::endl;
        _get_route.push_back(std::make_pair(std::regex(pattern),handler));
    }
    void Post(const std::string &pattern, const Handler &handler){
        _post_route.push_back(std::make_pair(std::regex(pattern),handler));
    }
    void Put(const std::string &pattern, const Handler &handler){
        _put_route.push_back(std::make_pair(std::regex(pattern),handler));
    }
    void Delete(const std::string &pattern, const Handler &handler){
        _delete_route.push_back(std::make_pair(std::regex(pattern),handler));
    }
    void SetThreadCount(int count){
        _server.SetThreadCount(count);
    }
    void Listen(){
        _server.Start();
    }
};

